
#ifndef __DRAWABLE__
#define __DRAWABLE__

#include "../meshdef/cgaltypes.h"

/// A Drawable is merely an object with a bounding box which supports a draw method.
struct Drawable {
    
    /// Object's bounding box
    Bbox box;    
    
    /// Default constructor
    Drawable () : box() {
    }
    
    /// Default constructor with bounding box
    Drawable (const Bbox& b) : box(b) {
    }

    /// Default destructor
    virtual ~Drawable () {
    }

    /// Default drawing does nothing
    virtual void draw () const {
      std::cout << "Drawing default method\n";
    }

};

/// An example of a Drawable: a Sphere of a given radius at the origin
struct Sphere : public Drawable
{
    /// Radius of the sphere
    float radius;
    
    /// Constructor
    Sphere(float r = 0.02);
    
    /// Default drawing
    virtual void draw () const;
};

/// Another example of a Drawable: a "dot", i.e., a point drawn as a circle
struct Dot : public Drawable
{
    /// Constructor
    /// @param wid width of the dot in pixels.
    Dot (float wid = 25.0);
    
    /// width of the dot in pixels
    float width;
    
    /// Default drawing
    virtual void draw () const;
};

/// A Sphere object
extern Sphere sphere;

/// A Dot object
extern Dot dot;

///
/// A Drawable instance is a drawable that may be instatiated in the scene
/// by means of a transformation matrix
///
struct DrawableInstance : public Drawable 
{
    /// Pointer to the enclosed object.
    Drawable * obj;
    
    /// Constructors
    DrawableInstance (Drawable* d, const Transformation& t);
    DrawableInstance (DrawableInstance& di);
    
    /// Draws the instance.
    virtual void draw () const;

    /// Alters the transformation
    virtual void setTransformation (const Transformation& t);
    
    /// Obtains the transformation
    inline Transformation getTransformation () { return transform; }
    
protected:
    /// Object-to-scene tranformation
    Transformation transform;
};

/// 
/// A DrawableInstanceGroup contains several drawable instances
///
struct DrawableInstanceGroup : public DrawableInstance
{
    /// Contains the children drawable instances
    std::vector<DrawableInstance*> group;

    /// Constructor
    DrawableInstanceGroup ();
    
    /// Adds one more instance to the group. Returns true if successful.
    /// Fails if instance was already in the group.
    bool add (DrawableInstance* instance);
    
    /// Adds one more instance to the group
    void clear () { group.clear (); };
    
    /// Returns the number of objects in the group
    unsigned int size() { return group.size (); }
    
    /// Propagates the group transformation to each of its children.
    /// Establishes the null transformation (identity matrix) for the group;
    void propagateTransformation ();
    
    /// Infers a translation transformation for the group from the average position of its
    /// children. The transformations of the children objects are also modified
    /// to take this into account. 
    void inferGroupTransformation ();
    
    /// Alters the transformation
    virtual void setTransformation (const Transformation& t);
    
    /// Draws the instance group.
    virtual void draw () const;
};

/// Performs a glMultMatrix where the matrix is a CGAL transformation.
/// @param t CGAL tranformation matrix.
void glTransform (const Transformation &t);

#endif
